package codec

import (
	"bufio"
	"errors"
	"fmt"
	"io"
)

// 定义刷新接口, 用于刷新主动刷新WriteTo
type writerFlush interface {
	io.Writer
	Flush() error
}

// ByteBuf 字节缓冲区
type ByteBuf struct {
	reader *bufio.Reader
	writer *bufio.Writer
}

func (b *ByteBuf) ReadBuffer() *bufio.Reader {
	return b.reader
}

func (b *ByteBuf) Read(p []byte) (n int, err error) {
	return b.reader.Read(p)
}

func (b *ByteBuf) ReadByte() (byte, error) {
	return b.reader.ReadByte()
}

func (b *ByteBuf) ReadInt() (int, error) {
	return ReadInt(b.reader)
}

func (b *ByteBuf) ReadBytes(size int) ([]byte, error) {
	bytes := make([]byte, size)
	if n, err := b.reader.Read(bytes); err != nil {
		return nil, err
	} else if n != size {
		return nil, fmt.Errorf("read %d byte(s) but expected %d", n, size)
	}
	return bytes, nil
}

func (b *ByteBuf) ReadAll() ([]byte, error) {
	data := make([]byte, 0)
	buf := make([]byte, b.reader.Size())
	for {
		if n, err := b.Read(buf); err != nil {
			if err == io.EOF {
				return data, nil
			}
			return nil, err
		} else {
			data = append(data, buf[:n]...)
		}
	}
}

func (b *ByteBuf) ReadLine() (string, error) {
	var readData []byte
	for {
		line, more, err := b.reader.ReadLine()
		if err != nil {
			return "", err
		}
		if line != nil {
			readData = append(readData, line...)
		}
		if more {
			continue
		}
		break
	}
	return string(readData), nil
}

func (b *ByteBuf) WriteTo(write io.Writer) (int64, error) {
	if b.reader == nil {
		return 0, errors.New("")
	}
	offset := int64(0)
	buff := make([]byte, b.reader.Size())
	for {
		size, err := b.Read(buff)
		if err == io.EOF {
			return offset, nil
		} else if err != nil {
			return offset, err
		}

		if _, err := write.Write(buff[:size]); err != nil {
			return offset, err
		}
		if flush, ok := write.(writerFlush); ok {
			if err := flush.Flush(); err != nil {
				return offset, err
			}
		}
		offset += int64(size)
	}
}

func (b *ByteBuf) WriteBuffer() *bufio.Writer {
	return b.writer
}

func (b *ByteBuf) Write(p []byte) (n int, err error) {
	return b.writer.Write(p)
}

func (b *ByteBuf) WriteByte(data byte) error {
	if err := b.writer.WriteByte(data); err != nil {
		return err
	}
	return nil
}

func (b *ByteBuf) WriteInt(data int) error {
	if n, err := b.writer.Write(IntToByteBigEndian(data)); n != 4 || err != nil {
		return err
	}
	return nil
}

func (b *ByteBuf) WriteBytes(data []byte) error {
	if n, err := b.writer.Write(data); err != nil {
		return err
	} else if n != len(data) {
		return fmt.Errorf("write %d byte(s) but expected %d", n, len(data))
	}
	return nil
}

func (b *ByteBuf) WriteString(data string) error {
	if _, err := b.writer.WriteString(data); err != nil {
		return err
	}
	return nil
}

func (b *ByteBuf) ReadFrom(reader io.Reader) (int64, error) {
	if b.writer == nil {
		return 0, fmt.Errorf("read from nil buffer")
	}

	offset := int64(0)
	buff := make([]byte, b.writer.Size())
	for {
		size, err := reader.Read(buff)
		if err == io.EOF {
			return offset, nil
		} else if err != nil {
			return offset, err
		}

		if err := b.WriteBytes(buff[:size]); err != nil {
			return offset, err
		}
		if err := b.Flush(); err != nil {
			return offset, err
		}
		offset += int64(size)
	}
}

func (b *ByteBuf) Flush() error {
	if b.writer != nil {
		if err := b.writer.Flush(); err != nil {
			return err
		}
	}
	return nil
}

func NewReadByteBuf(reader io.Reader) *ByteBuf {
	if buff, ok := reader.(*bufio.Reader); ok {
		return &ByteBuf{reader: buff}
	} else {
		return &ByteBuf{reader: bufio.NewReader(reader)}
	}
}

func NewWriteByteBuf(writer io.Writer) *ByteBuf {
	if buff, ok := writer.(*bufio.Writer); ok {
		return &ByteBuf{writer: buff}
	} else {
		return &ByteBuf{writer: bufio.NewWriter(writer)}
	}
}

func NewReadWriteByteBuf(reader io.Reader, writer io.Writer) *ByteBuf {
	byteBuf := &ByteBuf{}
	if buff, ok := reader.(*bufio.Reader); ok {
		byteBuf.reader = buff
	} else {
		byteBuf.reader = bufio.NewReader(reader)
	}
	if buff, ok := writer.(*bufio.Writer); ok {
		byteBuf.writer = buff
	} else {
		byteBuf.writer = bufio.NewWriter(writer)
	}
	return byteBuf
}
